package com.example.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.common.enums.CodeEnum;
import com.example.common.exception.ServiceException;
import com.example.common.utils.R;
import com.example.system.entity.AppointmentScheduler;
import com.example.system.entity.Department;
import com.example.system.entity.Doctor;
import com.example.system.entity.User;
import com.example.system.mapper.*;
import com.example.system.service.IAppointmentSchedulerService;
import com.example.system.service.IOrderService;
import com.example.system.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.rmi.server.ServerCloneException;
import java.sql.Time;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 王鹤蒲
 * @since 2024-01-29
 */
@Service
public class AppointmentSchedulerServiceImpl extends ServiceImpl<AppointmentSchedulerMapper, AppointmentScheduler> implements IAppointmentSchedulerService {

    @Autowired
    private AppointmentSchedulerMapper appointmentSchedulerMapper;

    @Autowired
    private IUserService iUserService;

    @Autowired
    private IOrderService iOrderService;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private DepartmentMapper departmentMapper;

    @Autowired
    private DoctorMapper doctorMapper;

    @Override
    public R insert(AppointmentScheduler appointmentScheduler) {
        LambdaQueryWrapper<AppointmentScheduler> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(AppointmentScheduler::getDoctorId,appointmentScheduler.getDoctorId());
        lambdaQueryWrapper.eq(AppointmentScheduler::getWorkDate,appointmentScheduler.getWorkDate());
        lambdaQueryWrapper.eq(AppointmentScheduler::getDayPart,appointmentScheduler.getDayPart());
        if(appointmentSchedulerMapper.exists(lambdaQueryWrapper)){
            return R.error(CodeEnum.SCHEDULING_INFORMATION_CONFLICT.getCode(),CodeEnum.SCHEDULING_INFORMATION_CONFLICT.getMsg());
        }
        LocalDateTime createTime=LocalDateTime.now();
        appointmentScheduler.setEndTime(appointmentScheduler.getStartTime().plusMinutes(appointmentScheduler.getReservedNumber()*15)).setAvailableNumber(appointmentScheduler.getReservedNumber()).setDepartmentId(doctorMapper.selectById(appointmentScheduler.getDoctorId()).getDepartmentId()).setCreateBy(iUserService.getCurrentLoginUser().getUserName()).setCreateTime(createTime);
        appointmentSchedulerMapper.insert(appointmentScheduler);
        return R.success();
    }


    @Override
    public R selectAll(Integer currentPage, Integer pageSize, Integer doctorId, Integer departmentId, LocalDate workDate, String dayPart, String status) {
       Page<AppointmentScheduler> page=new Page(currentPage,pageSize);
       return R.success( appointmentSchedulerMapper.findByPage(page,doctorId,departmentId,workDate,dayPart,status));
    }

    @Override
    public R edit(AppointmentScheduler appointmentScheduler) {
        LambdaQueryWrapper<AppointmentScheduler> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(AppointmentScheduler::getDoctorId,appointmentScheduler.getDoctorId());
        lambdaQueryWrapper.eq(AppointmentScheduler::getWorkDate,appointmentScheduler.getWorkDate());
        lambdaQueryWrapper.eq(AppointmentScheduler::getDayPart,appointmentScheduler.getDayPart());
        if(appointmentSchedulerMapper.exists(lambdaQueryWrapper)){
            return R.error(CodeEnum.SCHEDULING_INFORMATION_CONFLICT.getCode(),CodeEnum.SCHEDULING_INFORMATION_CONFLICT.getMsg());
        }
        LocalDateTime updateTime=LocalDateTime.now();
        Integer registrationNumber = appointmentSchedulerMapper.selectById(appointmentScheduler.getId()).getReservedNumber() - appointmentScheduler.getAvailableNumber();
        if(appointmentScheduler.getReservedNumber()<registrationNumber) {
            return R.error(CodeEnum.MODIFY_ERROR.getCode(),CodeEnum.MODIFY_ERROR.getMsg());
        }
        if(appointmentScheduler.getReservedNumber()==registrationNumber){
            appointmentScheduler.setStatus("0");
        }

        appointmentScheduler.setEndTime(appointmentScheduler.getStartTime().plusMinutes(appointmentScheduler.getReservedNumber()*15)).setAvailableNumber(appointmentScheduler.getReservedNumber()-registrationNumber).setUpdateBy(iUserService.getCurrentLoginUser().getUserName()).setUpdateTime(updateTime);
        appointmentSchedulerMapper.updateById(appointmentScheduler);
        return R.success();
    }

    @Override
    public R deleteById(Integer id) {
        LocalDateTime updateTime=LocalDateTime.now();
        LambdaUpdateWrapper<AppointmentScheduler> lambdaUpdateWrapper=new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.set(AppointmentScheduler::getUpdateBy,iUserService.getCurrentLoginUser().getUserName());
        lambdaUpdateWrapper.set(AppointmentScheduler::getUpdateTime,updateTime);
        lambdaUpdateWrapper.set(AppointmentScheduler::getDelFlag,'1');
        lambdaUpdateWrapper.set(AppointmentScheduler::getStatus,"-1");
        lambdaUpdateWrapper.eq(AppointmentScheduler::getId,id);
        appointmentSchedulerMapper.update(new AppointmentScheduler(),lambdaUpdateWrapper);
        return R.success();
    }

    @Override
    public R deleteByIds(Integer[] ids) {
        LocalDateTime updateTime=LocalDateTime.now();
        LambdaUpdateWrapper<AppointmentScheduler> lambdaUpdateWrapper=new LambdaUpdateWrapper<>();
        for(Integer id:ids){
            lambdaUpdateWrapper.set(AppointmentScheduler::getUpdateBy,iUserService.getCurrentLoginUser().getUserName());
            lambdaUpdateWrapper.set(AppointmentScheduler::getUpdateTime,updateTime);
            lambdaUpdateWrapper.set(AppointmentScheduler::getDelFlag,"1");
            lambdaUpdateWrapper.set(AppointmentScheduler::getStatus,"-1");
            lambdaUpdateWrapper.eq(AppointmentScheduler::getId,id);
            appointmentSchedulerMapper.update(new AppointmentScheduler(),lambdaUpdateWrapper);
            lambdaUpdateWrapper.clear();
        }
        return R.success();
    }

    @Override
    public R getDepartmentAppointmentSchedulerInfos(Integer currentPage, Integer pageSize, Integer departmentId) {
        Page<AppointmentScheduler> page=new Page<>(currentPage,pageSize);
        Page<AppointmentScheduler> pageResult=appointmentSchedulerMapper.findAppointmentSchedulerInfosByDepartmentId(page,departmentId);
        List<AppointmentScheduler> appointmentSchedulerList=pageResult.getRecords().stream().map(appointmentScheduler -> appointmentScheduler.setDayOfWeek(getDayOfWeek(appointmentScheduler.getWorkDate()))).collect(Collectors.toList());
        pageResult.setRecords(appointmentSchedulerList);
        return R.success(pageResult);
    }





    @Override
    public R selectAppointmentSchedulerDetailInfos(Integer departmentId, String workDate) {
        List<AppointmentScheduler> morningAppointmentSchedulerDetailInfos=appointmentSchedulerMapper.selectAppointmentSchedulerDetailInfos(departmentId,workDate,"0");
        List<AppointmentScheduler> afternoonAppointmentSchedulerDetailInfos=appointmentSchedulerMapper.selectAppointmentSchedulerDetailInfos(departmentId,workDate,"1");
        Map<String,Object> appointmentSchedulerDetailInfosMap=new HashMap<>();
        appointmentSchedulerDetailInfosMap.put("morningAppointmentSchedulerDetailInfos",morningAppointmentSchedulerDetailInfos);
        appointmentSchedulerDetailInfosMap.put("afternoonAppointmentSchedulerDetailInfos",afternoonAppointmentSchedulerDetailInfos);
        return R.success(appointmentSchedulerDetailInfosMap);
    }

    @Override
    public R getDepartmentAppointmentScheduler(Integer departmentId, String startDate, String endDate) {
        List<AppointmentScheduler> appointmentSchedulerList=appointmentSchedulerMapper.findDepartmentAppointmentScheduler(departmentId,startDate,endDate);
        List<Map<String,String>> appointmentSchedulerMapList=new ArrayList<>();
        DateTimeFormatter dateTimeFormatter=DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate localDate=LocalDate.parse(startDate,dateTimeFormatter);
        LocalDate endLocalDate=LocalDate.parse(endDate,dateTimeFormatter);
        while(localDate.isBefore(endLocalDate) || localDate.isEqual(endLocalDate)){
             Map<String,String> appointmentSchedulerMap=new HashMap<>();
             appointmentSchedulerMap.put("date",localDate.format(dateTimeFormatter));
             for(int i=0;i<appointmentSchedulerList.size();i++){
                  if(localDate.isEqual(appointmentSchedulerList.get(i).getWorkDate())){
                      if(appointmentSchedulerList.get(i).getAvailableNumber()==0){
                          appointmentSchedulerMap.put("status","0");
                      }else{
                          appointmentSchedulerMap.put("status","1");
                      }
                      break;
                  }
             }
             if(!appointmentSchedulerMap.containsKey("status")){
                 appointmentSchedulerMap.put("status","-1");
             }
             appointmentSchedulerMapList.add(appointmentSchedulerMap);
             localDate=localDate.plusDays(1);
        }
        return R.success(appointmentSchedulerMapList);
    }

    @Override
    public R getAppointmentTimeList(Integer appointmentSchedulerId) {
        List<Map<String,Object>> invalidAppointTimeList=orderMapper.getInvalidAppointmentTimeList(appointmentSchedulerId);
        System.out.println(invalidAppointTimeList);
        LambdaQueryWrapper<AppointmentScheduler> appointmentSchedulerLambdaQueryWrapper=new LambdaQueryWrapper<>();
        appointmentSchedulerLambdaQueryWrapper.eq(AppointmentScheduler::getDelFlag,"0");
        appointmentSchedulerLambdaQueryWrapper.eq(AppointmentScheduler::getStatus,"1");
        appointmentSchedulerLambdaQueryWrapper.eq(AppointmentScheduler::getId,appointmentSchedulerId);
        AppointmentScheduler appointmentScheduler=appointmentSchedulerMapper.selectOne(appointmentSchedulerLambdaQueryWrapper);
        LocalTime startTime=appointmentScheduler.getStartTime();
        LocalTime endTime=appointmentScheduler.getEndTime();
        List<Map<String,Object>> appointmentTimeList=new ArrayList<Map<String,Object>>();
        LocalTime time=startTime;
        while(time.isBefore(endTime)){
            Map<String,Object> appointmentTimeMap=new HashMap<>();
            appointmentTimeMap.put("appointmentTime",time.format(DateTimeFormatter.ISO_LOCAL_TIME));
            appointmentTimeMap.put("finishTime",time.plusMinutes(15).format(DateTimeFormatter.ISO_LOCAL_TIME));
            appointmentTimeMap.put("status","1");
           for(int i=0;i<invalidAppointTimeList.size();i++){
           LocalTime invalidAppointTime=Time.valueOf(invalidAppointTimeList.get(i).get("appointment_time").toString()).toLocalTime();
           String status=invalidAppointTimeList.get(i).get("status").toString();
           if(time.equals(invalidAppointTime)){
               if("0".equals(status)){
               appointmentTimeMap.put("status","0");
               }else{
               appointmentTimeMap.put("status","-1");
               }
               break;
           }
           }
           appointmentTimeList.add(appointmentTimeMap);
           time=time.plusMinutes(15);
        }
        System.out.println(appointmentTimeList);
        return R.success(appointmentTimeList);
    }

    @Override
    public R suspend(Integer appointmentSchedulerId, String suspendReason) {
         LambdaUpdateWrapper<AppointmentScheduler> lambdaUpdateWrapper=new LambdaUpdateWrapper<>();
         lambdaUpdateWrapper.eq(AppointmentScheduler::getId,appointmentSchedulerId);
         lambdaUpdateWrapper.set(AppointmentScheduler::getStatus,"-1");
         lambdaUpdateWrapper.set(AppointmentScheduler::getSuspendReason,suspendReason);
         lambdaUpdateWrapper.set(AppointmentScheduler::getUpdateBy,iUserService.getCurrentLoginUser().getUserName());
         lambdaUpdateWrapper.set(AppointmentScheduler::getUpdateTime,LocalDateTime.now());
         appointmentSchedulerMapper.update(new AppointmentScheduler(),lambdaUpdateWrapper);
         AppointmentScheduler appointmentScheduler=appointmentSchedulerMapper.selectById(appointmentSchedulerId);
         User user=userMapper.selectById(doctorMapper.selectById(appointmentScheduler.getDoctorId()).getUserId());
         Department department=departmentMapper.selectById(appointmentScheduler.getDepartmentId());
         List<String> registeredUserEmailList= orderMapper.getRegisteredUserEmailList(appointmentSchedulerId);
         String subject ="停诊通知";
         String dayPart="上午";
         if("1".equals(appointmentScheduler.getDayPart())){
             dayPart="下午";
         }
         String message="您预约的"+appointmentScheduler.getWorkDate()+" "+dayPart+" "+department.getName()+" "+user.getUserName()+"的门诊已停诊，请及时前往取消预约，以免延误您的看诊。";
         registeredUserEmailList.forEach(registeredUserEmail->{
         iOrderService.sendMailReminder(registeredUserEmail,subject,message);
         });
         return R.success();
    }

    @Override
    public R selectSuspendNoticeList() {
        List<Map<String,Object>> suspendNoticeList =appointmentSchedulerMapper.selectSuspendNoticeList();
        suspendNoticeList.forEach(suspendNoticeMap->{
            String dayPart="上午";
           if("1".equals(suspendNoticeMap.get("dayPart").toString())){
               dayPart="下午";
           }
            LocalDate workDate=LocalDate.parse(suspendNoticeMap.get("workDate").toString());
            LocalDateTime updateTime=LocalDateTime.parse(suspendNoticeMap.get("updateTime").toString());
            suspendNoticeMap.put("workDate",workDate.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
            suspendNoticeMap.put("updateTime",updateTime.format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm")));
            suspendNoticeMap.put("dayPart",dayPart);
        });
        return R.success(suspendNoticeList);
    }


    public String getDayOfWeek(LocalDate date){
      String dayOfWeek="";
      switch (date.getDayOfWeek()){
          case SUNDAY: dayOfWeek="星期日"; break;
          case MONDAY: dayOfWeek="星期一"; break;
          case TUESDAY: dayOfWeek="星期二"; break;
          case WEDNESDAY: dayOfWeek="星期三"; break;
          case THURSDAY: dayOfWeek="星期四"; break;
          case FRIDAY: dayOfWeek="星期五"; break;
          case SATURDAY: dayOfWeek="星期六"; break;
          default: break;
      }
    return dayOfWeek;
     }

}
